"""
Grave! Important! Важно!

Proletoj el ĉiuj landoj, unuiĝu!
Workers of the world, unite!
Пролетарии всех стран, соединяйтесь!

https://tkom.pro
"""

import sys
from django.db import models
from django.db.models import Q, Max
from django.utils.translation import gettext_lazy as _
from main.models import SiriusoBazaAbstraktaKomunumoj, \
    SiriusoTipoAbstrakta, Uzanto
from siriuso.models.postgres import CallableEncoder
from siriuso.utils import default_lingvo, perms
from django.contrib.auth.models import Permission


# Энциклопедия

# Типы категорий Энциклопедии, использует абстрактный класс SiriusoTipoAbstrakta
class EnciklopedioKategorioTipo(SiriusoTipoAbstrakta):

    # многоязычное название в JSON формате
    nomo = models.JSONField(verbose_name=_('Nomo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'enciklopedio_kategorioj_tipoj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Tipo de kategorioj enciklopedio')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Tipoj de kategorioj enciklopedio')
        # права
        permissions = (
            ('povas_vidi_kategorian_tipon', _('Povas vidi kategorian tipon')),
            ('povas_krei_kategorian_tipon', _('Povas krei kategorian tipon')),
            ('povas_forigi_kategorian_tipon', _('Povas forigu kategorian tipon')),
            ('povas_shanghi_kategorian_tipon', _('Povas ŝanĝi kategorian tipon')),
        )

    @staticmethod
    def _get_perm_cond(user_obj):
        return Q()


# Категории Энциклопедии
class EnciklopedioKategorio(SiriusoBazaAbstraktaKomunumoj):

    # ID записи для вывода
    id = models.IntegerField(_('ID'), unique=True, default=0)

    # тип категории Энциклопедии
    tipo = models.ForeignKey(EnciklopedioKategorioTipo, verbose_name=_('Tipo'), blank=False, default=None,
                             on_delete=models.CASCADE)

    # код
    kodo = models.CharField(_('Kodo'), max_length=32)

    # название
    nomo = models.JSONField(verbose_name=_('Titolo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # описание в таблице описаний категории, от туда будет браться описание с нужным языковым тегом
    priskribo = models.JSONField(verbose_name=_('Priskribo'), blank=True, null=False, default=default_lingvo,
                                   encoder=CallableEncoder)

    # администраторы категории
    administrantoj = models.ManyToManyField('main.Uzanto', verbose_name=_('Enciklopedio administrantoj'),
                                            related_name='enciklopediokategorio_administrantoj')

    # модераторы категории
    moderatoroj = models.ManyToManyField('main.Uzanto', verbose_name=_('Enciklopedio moderatoroj'),
                                         related_name='enciklopediokategorio_moderatoroj')

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'enciklopedio_kategorioj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Kategorio enciklopedio')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Kategorioj enciklopedio')
        # права
        permissions = (
            ('povas_vidi_kategorion', _('Povas vidi kategorion')),
            ('povas_krei_kategorion', _('Povas krei kategorion')),
            ('povas_forigi_kategorion', _('Povas forigu kategorion')),
            ('povas_shanghi_kategorion', _('Povas ŝanĝi kategorion')),
        )

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # для представления объекта будет выведено поле id этой модели
        return '{}'.format(self.id)

    # реализация автоинкремента при сохранении
    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        if self.id is None or not self.id:
            model = getattr(sys.modules[self.__module__], self.__class__.__name__)
            next_id = model.objects.all().aggregate(Max('id'))['id__max']

            if next_id is None:
                next_id = 1
            else:
                next_id += 1
            super(model, self).__setattr__('id', next_id)

        super(EnciklopedioKategorio, self).save(force_insert=force_insert, force_update=force_update, using=using,
                                            update_fields=update_fields)

    def _get_user_permissions(self, user_obj):
        user_perms = Permission.objects.none()

        if user_obj.is_authenticated:
            if self.autoro == user_obj:
                all_perms = set(perms.user_registrita_perms(apps=('enciklopedio',)))
            else:
                all_perms = set()

            all_perms = set(perm.split('.')[-1] for perm in all_perms if perm in (
                'enciklopedio.povas_vidi_kategorion', 'enciklopedio.povas_krei_kategorion',
                'enciklopedio.povas_forigi_kategorion', 'enciklopedio.povas_shanghi_kategorion',
                'enciklopedio.povas_krei_pagxan'
            ))

            user_perms = Permission.objects.filter(content_type__app_label='enciklopedio', codename__in=all_perms)

        return user_perms

    def _get_group_permissions(self, user_obj):
        return Permission.objects.none()

    @staticmethod
    def _get_perm_cond(user_obj):
        if user_obj.is_authenticated:
            # Для авторизированного пользователя
            if (perms.has_registrita_perm('enciklopedio.povas_vidi_kategorion')
                    or user_obj.has_perm('enciklopedio.povas_vidi_kategorion')):
                # Если есть право просмотра у зарегистрированного или есть право Django у пользователя
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        else:
            # Для неавторизированных пользователей
            if perms.has_neregistrita_perm('enciklopedio.povas_vidi_kategorion'):
                # Если есть права на просмотр
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        return cond

# Типы страниц Энциклопедии, использует абстрактный класс SiriusoTipoAbstrakta
class EnciklopedioPagxoTipo(SiriusoTipoAbstrakta):

    # многоязычное название в JSON формате
    nomo = models.JSONField(verbose_name=_('Nomo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'enciklopedio_pagxo_tipoj'
        # читабельное название модели, в единственном числе
        verbose_name = _('Tipo de pagxoj de enciklopedio')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Tipoj de pagxoj de enciklopedio')
        # права
        permissions = (
            ('povas_vidi_pagxan_tipon', _('Povas vidi pagxan tipon')),
            ('povas_krei_pagxan_tipon', _('Povas krei pagxan tipon')),
            ('povas_forigi_pagxan_tipon', _('Povas forigu pagxan tipon')),
            ('povas_shanghi_pagxan_tipon', _('Povas ŝanĝi pagxan tipon')),
        )

    @staticmethod
    def _get_perm_cond(user_obj):
        return Q()


# Страницы Энциклопедии
class EnciklopedioPagxo(SiriusoBazaAbstraktaKomunumoj):

    # ID записи для вывода
    id = models.IntegerField(_('ID'), unique=True, default=0)

    # тип страниц Энциклопедии
    tipo = models.ForeignKey(EnciklopedioPagxoTipo, verbose_name=_('Tipo'), blank=False, default=None,
                             on_delete=models.CASCADE)

    # код
    kodo = models.CharField(_('Kodo'), max_length=32)

    # название
    nomo = models.JSONField(verbose_name=_('Titolo'), blank=True, null=False, default=default_lingvo,
                              encoder=CallableEncoder)

    # текст многоязычный в JSON формате
    teksto = models.JSONField(verbose_name=_('Teksto'), blank=True, null=False, default=default_lingvo,
                                encoder=CallableEncoder)

    # категория
    kategorio = models.ManyToManyField(EnciklopedioKategorio, verbose_name=_('Kategorio'),
                                  related_name='enciklopediopagxo_kategorio')

    # администраторы категории
    administrantoj = models.ManyToManyField('main.Uzanto', verbose_name=_('Enciklopedio administrantoj'),
                                            related_name='enciklopediopagxo_administrantoj')

    # модераторы категории
    moderatoroj = models.ManyToManyField('main.Uzanto', verbose_name=_('Enciklopedio moderatoroj'),
                                         related_name='enciklopediopagxo_moderatoroj')

    # дополнительные настройки для модели
    class Meta:
        # название таблицы в базе данных для этой модели
        db_table = 'enciklopedio_pagxo'
        # читабельное название модели, в единственном числе
        verbose_name = _('Pagxo de enciklopedio')
        # читабельное название модели, во множественном числе
        verbose_name_plural = _('Pagxoj de enciklopedio')
        # права
        permissions = (
            ('povas_vidi_pagxan', _('Povas vidi pagxan')),
            ('povas_krei_pagxan', _('Povas krei pagxan')),
            ('povas_forigi_pagxan', _('Povas forigu pagxan')),
            ('povas_shanghi_pagxan', _('Povas ŝanĝi pagxan')),
        )

    # выбор объекта для отображения в интерфейсах, в том числе администратора
    def __str__(self):
        # для представления объекта будет выведено поле id этой модели
        return '{}'.format(self.id)

    # реализация автоинкремента при сохранении
    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        if self.id is None or not self.id:
            model = getattr(sys.modules[self.__module__], self.__class__.__name__)
            next_id = model.objects.all().aggregate(Max('id'))['id__max']

            if next_id is None:
                next_id = 1
            else:
                next_id += 1
            super(model, self).__setattr__('id', next_id)

        super(EnciklopedioPagxo, self).save(force_insert=force_insert, force_update=force_update, using=using,
                                            update_fields=update_fields)

    def _get_user_permissions(self, user_obj):
        user_perms = Permission.objects.none()

        if user_obj.is_authenticated:
            if self.autoro == user_obj:
                all_perms = set(perms.user_registrita_perms(apps=('enciklopedio',)))
            else:
                all_perms = set()

            all_perms = set(perm.split('.')[-1] for perm in all_perms if perm in (
                'enciklopedio.povas_vidi_pagxan', 'enciklopedio.povas_krei_pagxan',
                'enciklopedio.povas_forigi_pagxan', 'enciklopedio.povas_shanghi_pagxan'
            ))

            user_perms = Permission.objects.filter(content_type__app_label='enciklopedio', codename__in=all_perms)

        return user_perms

    def _get_group_permissions(self, user_obj):
        return Permission.objects.none()

    @staticmethod
    def _get_perm_cond(user_obj):
        if user_obj.is_authenticated:
            # Для авторизированного пользователя
            if (perms.has_registrita_perm('enciklopedio.povas_vidi_pagxan')
                    or user_obj.has_perm('enciklopedio.povas_vidi_pagxan')):
                # Если есть право просмотра у зарегистрированного или есть право Django у пользователя
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        else:
            # Для неавторизированных пользователей
            if perms.has_neregistrita_perm('enciklopedio.povas_vidi_kategorion'):
                # Если есть права на просмотр
                cond = Q()
            else:
                # Если права нет, то задаем заведомо невыполнимое условие, например, первичный ключ равен NULL
                cond = Q(uuid__isnull=True)

        return cond
